%define CLONE_VM        0x00100        ;Clone virtual memory
%define CLONE_FS        0x00200        ;Clone file system
%define CLONE_FILES     0x00400        ;Clone files
%define CLONE_SIGNHAND  0x00800        ;Clone signal hangler
%define CLONE_THREAD    0x10000        ;Clone as thread

%define SIGCHLD         0x00011        ;Signal to be delivered to the main thread

%define PROT_READ       0x00001        ;Makes memory readable
%define PROT_WRITE      0x00002        ;Makes memory writeable

%define MAP_PRIVATE     0x00002        ;Maps private memory
%define MAP_ANON        0x00020        ;Maps anonymous memory
%define MAP_GROWSDOWN   0x00100        ;Maps stack like segment (expands to lower addresses)

;   System calls
%define SYS_EXIT_GROUP  231            
%define SYS_MMAP        9
%define SYS_EXIT        60
%define SYS_WRITE       1
%define SYS_GETPID      39
%define SYS_GETTID      186
%define SYS_CLONE       56
%define SYS_NANOSLEEP   35

;======================= map_stack =====================================
;void*  map_stack(unsigned long stack_size)
global map_stack
map_stack:
    ;Save registers
    push    rdi
    push    rsi
    push    rdx
    push    r10
    push    r8
    push    r9
    
    mov     rsi, rdi                                        ;Size of requested memory allocation
    xor     rdi, rdi                                        ;Prefered address (0)
    mov     rdx, PROT_READ | PROT_WRITE                    ;Protection for allocated region
    mov     r10, MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN   ;Mapping attributes
    xor     r8, r8                                          ;fd = -1
    dec     r8
    xor     r9, r9                                          ;Offset - irrelevant (0)
    mov     rax, SYS_MMAP
    syscall
    
    pop r9
    pop r8
    pop r10
    pop rdx
    pop rsi
    pop rdi
    ;Restore registers
    ret

;======================= create_thread =================================
;long   create_thread(void (*thread_func)(void*), void* param)
global create_thread
create_thread:
    mov     r14, rdi
    mov     r15, rsi
    
    mov     rdi, 0x1000             ;   Allocate stack
    call    map_stack

    mov     rsi, rax                ;   Clone
    ;xor            rsi, rsi
    mov     rdi, CLONE_VM | CLONE_FS | CLONE_THREAD | CLONE_SIGNHAND | SIGCHLD
    xor     r10, r10
    xor     r8,  r8
    xor     r9,  r9
    mov     rax, SYS_CLONE
    syscall
    
    cmp     rax, 0
    jnz     .parent
    
    ;mov        rdi, r14
    ;mov        rsi, r15
    push    r14
    mov     rdi, r15
    ret
    
.parent:
    ret
    
;======================= exit_thread ===================================
;void   exit_thread(long result)
global exit_thread
exit_thread:
    mov     rax, SYS_EXIT
    syscall